From Noob to PRO Python Calculator: Part 1 — From Basics to Functions
Photo by David Clode on Unsplash

Creating a basic calculator is an excellent project for Python beginners. This tutorial walks you through building a simple four-function calculator, step-by-step, improving it incrementally by handling errors and introducing functions. By the end of this guide, you’ll have a more robust and reusable piece of code, setting a solid foundation for more advanced features in the upcoming parts.

1. Beginner

This is straight from my other guide. It involves nothing but the very basic minimum you need for a working 4-function calculator. There’s nothing to talk about here, if you don’t understand something then go ahead and go through that guide :)

Create a file called calculator.py and type in the following code:

x = int(input('Enter a number: '))
y = int(input('Enter another number: '))
operation = input('Enter an operation (+, -, *, /): ')

if (operation == '+'):
  print(x+y)
elif (operation == '-'):
  print(x-y)
elif (operation == '*'):
  print(x*y)
elif (operation == '/'):
  print(x/y)
else:
  print("I do not understand that operation")

How can we improve this?

There’s quite a lot to improve here, for starters:

  • If we try to divide 1 by 0, then the computer gets mad and throws out a big error at us
  • The user can be naughty and can enter alphabets and punctuations instead of numbers and the computer will get mad at us.
  • We can’t input decimal numbers which are pretty important for a calculator
  • We gotta run the function again and again if we need to do multiple calculations

Let’s work on some of these and then see where we are

2. Handling division by 0

This is easy to do. You check whether or not the y value in x/y is 0. If it is 0, you print it “NO! don’t do that”, otherwise you go ahead with the calculation.

# calculator.py

x = int(input('Enter a number: '))
y = int(input('Enter another number: '))
operation = input('Enter an operation (+, -, *, /): ')

if (operation == '+'):
  print(x+y)
elif (operation == '-'):
  print(x-y)
elif (operation == '*'):
  print(x*y)
elif (operation == '/'):

  # Checking if y is 0, if it isn't then all is well.
  if (y == 0):
    print('Cannot divide by 0 you dummy')
  else:
    print(x/y)

else:
  print("I do not understand that operation")

We still have the problem that the user can

3. Input Type Checking

We must do the following steps 3 times:

  • Get the input from the user
  • Check if the input is what we want
  • If the input is bad, then yell at the user and ask them to try again

Getting the value of x and y

Take a look at the code to get the x value. We first prompt the user for an input: x = input('Enter a number: ')

Then we use a while loop. A while loop runs a piece of code again and again and again and again as long as some condition is met. Our condition here is that x is a number. Python spoon-feeds us this by already having a function to check if a string is numeric or not. It is isnumeric() . This returns True if the string is numeric, otherwise it returns False :

while (not x.isnumeric()):

So, we keep on asking the user for the input as long as the input by the user is not numeric.

Note: x.isnumeric() does not check if x is a number, all it checks is whether all its characters contains the digits 0–9. Python will still treat x as a string and not a number. Also if x is 3.14, the isnumeric() function will think that x is not a number since the decimal point “.” is not a number.

print('x is not numeric, enter again: ')

x = input('Enter a number: ')

Getting the operation from the user

Since the operation is not a number but a single character, we have different logic. Though everything else is the same, all we gotta check in the while loop condition is that the operation is one of the 4 accepted ones.

So we have: while (operation not in ['+', '-', '*', '/']):

The beauty about python is that its code can simply be read in english to understand what it is doing: “While the operation is not in that list of characters…”, then we tell the user that we can’t accept that input and ask for the input again.

Finally, we still gotta tell the python that x and y are numbers, not strings, so we just type in: x = int(x) to reassign x to its value casted to an int.

# calculator.py
x = input('Enter a number: ')
while (not x.isnumeric()):
  print('x is not numeric, enter again: ')
  x = input('Enter a number: ')

y = input('Enter a number: ')
while (not y.isnumeric()):
  print('y is not numeric, enter again: ')
  y = input('Enter a number: ')

operation = input('Enter an operation (+, -, *, /): ')
while (operation not in ['+', '-', '*', '/']):
  print('The operationis not among +, -, *, and /, enter again: ')
  operation = input('Enter an operation (+, -, *, /): ')

x = int(x)
y = int(y)

# The code to calculate remains the same

Notice that our results are pretty bland. When we enter something like 3+5, all we get is 8. We can do better by printing out the calculation and then the result. We do this by using template strings.

4. Better Outputs with Template Strings

Template strings, are also called format strings, or their original name: Interpolated strings. This is when we add Python logic in the middle of a string.

For example, if we were to print out a statement like “3+5 = 8”, we might’ve have typed: print("3+5=8") previously. But look at this new code:

print(f"3+5 = {3+5}") . By adding that f before the string, we’re telling Python that this is not just any string, but a format string. Here instead of us doing the calculation 3+5, we can put it between the curly brackets {} and tell python to do the calculation for us. This is becomes very helpful with variables. Look at the following code:

your_age = 17
friends_age = 20
print(f"The difference between your ages is {friends_age - your_age}"

Now, we might change both the variables and not have to do the calculation all the time. So in the calculator, if we’re doing a calculation like 3+5 = 8, we can print out something like this: print(f"{x}+{y}={x+y}") .

Python will fill in the variables and do the calculation for us at run time.

# calculator.py

# The code to get the input from the user remains the same

if (operation == '+'):
  print(f'{x} + {y} = {x+y}')
elif (operation == '-'):
  print(f'{x} - {y} = {x-y}')
elif (operation == '*'):
  print(f'{x} * {y}: {x*y}')
elif (operation == '/'):
  if (y == 0):
    print('Cannot divide by 0 you dummy')
  else:
    print(f'{x} / {y} = {x/y}')
else:
  print("I do not understand that operation")

So our code till now is:

x = input('Enter a number: ')
while (not x.isnumeric()):
  print('x is not numeric, enter again: ')
  x = input('Enter a number: ')

y = input('Enter a number: ')
while (not x.isnumeric()):
  print('y is not numeric, enter again: ')
  y= input('Enter a number: ')

operation = input('Enter an operation (+, -, *, /): ')
while (operation not in ['+', '-', '*', '/']):
  print('The operationis not among +, -, *, and /, enter again: ')
  operation = input('Enter an operation (+, -, *, /): ')

x = int(x)
y = int(y)

if (operation == '+'):
  print(f'{x} + {y} = {x+y}')
elif (operation == '-'):
  print(f'{x} - {y} = {x-y}')
elif (operation == '*'):
  print(f'{x} * {y}: {x*y}')
elif (operation == '/'):
  if (y == 0):
    print('Cannot divide by 0 you dummy')
  else:
    print(f'{x} / {y} = {x/y}')
else:
  print("I do not understand that operation")

Notice how we had to copy paste the code for getting x and y . What if in the future we needed another variable z or maybe 10 other variables. We can’t keep copy pasting the code because firstly, it looks ugly, secondly, its too much effort. What if we can give a label to just that piece of code and tell Python: “Hey, everything I type in this label, do that piece of code for me”. We can do this with functions.

5. Functions UNLEASHED!

Technically, everything you can do normally can be done as a function. This is known as functional programming.

We define a function with the following command:

def function_name(inputs):
  # what to do?
  return something

The def is a short-form of “define”. it is telling python to define the function, give it the name function_name . The function will take in a few inputs and then do something with it. Then at the end, it will return something. For example:

def square(x):
  return x**2

This function is named “square”. It takes in some variable x, and then returns its square.

Every time you see The curly brackets in Python (), it is a function. The print() is also a function. It takes in a few things and then displays that on the screen. Notice that the print function doesn’t return anything to us. We don’t get a value back in a code, everything just gets sent to the screen. Similarly, python has help(), type(), len() functions to do various things. The len() stands for “length”. It takes in a list of numbers and returns the length of the list.

So, let’s make a function to get the x and y values from the user:

def get_numeric_input():
  input_var= input('Enter a number: ')
  while (not input_var.isnumeric()):
    print('The input is not numeric, enter again: ')
    input_var = input('Enter a number: ')

  return int(input_var)

Compare it to the original code:

x = input('Enter a number: ')
while (not x.isnumeric()):
  print('x is not numeric, enter again: ')
  x = input('Enter a number: ')

x = int(x)

I’ve given it the name get_numeric_input . You can change this to whatever you want as long as you comply with Python’s naming conventions. The function takes in nothing. It just does the same thing we did, but in place of writing x, I’ve written input_var . This is because, since we’re using the same function to get the value of x and y, it will get confusing if we name the variable x. We gotta name it something else.

Note: A variable defined within the indentation of a function only exists within a function. If you try to print out input_var outside of the function, Python will get mad at you.

We do the same to get the operation. Now, of course since we’re only using the code once, we don’t technically need it, but we’re priming this up for a later upgrade.

def get_operation_input():
  input_var = input('Enter an operation (+, -, *, /): ')
  while (input_var not in ['+', '-', '*', '/']):
    print('The operationis not among +, -, *, and /, enter again: ')
    input_var = input('Enter an operation (+, -, *, /): ')
  
  return input_var

You’ll see that the logic is exactly like the original code to get the operation:

operation = input('Enter an operation (+, -, *, /): ')
while (operation not in ['+', '-', '*', '/']):
  print('The operationis not among +, -, *, and /, enter again: ')
  operation = input('Enter an operation (+, -, *, /): ')

Finally, let’s add a few more functions because why not? For each of the calculations we need to do, let’s make a function for them:

def add(x, y): return x+y
def subtract(x, y): return x-y
def multiply(x, y): return x*y
def divide(x, y):
  if (y == 0):
    return 'Cannot divide by 0 you dummy'
  else:
    return x/y

Note that for functions like add , since there is only a single line, we don’t need to put it in a new line and indent it, we can simply keep it next to the name.

We can also just put the code to check the operation and do the calculation as needed in a new function of its own:

def calculate(x, y, operation):
  if (operation == '+'):
    return f'{x} + {y} = {add(x, y)}'
  elif (operation == '-'):
    return f'{x} - {y} = {subtract(x, y)}'
  elif (operation == '*'):
    return f'{x} * {y} = {multiply(x, y)}'
  elif (operation == '/'):
    return f'{x} / {y} = {divide(x, y)}'
  else:
    return "I do not understand that operation"

Notice we need 3 inputs in this case: x, y, and the operation. Since everything is a function right now, we don’t have a variable named operation , so we need to keep it as a function parameter. Again, we don’t really need to do this now, but it will make sense in a few more iterations of this code.

All we’ve done is define the functions. To define a function is not the same as to run it. Python will store them somewhere in memory, but won’t actually do the things we ask it to do. We need to explicitely run the functions. To run all this, we just need 4 lines of code:

x = get_numeric_input()
y = get_numeric_input()
operation = get_operation_input()
print(calculate(x, y, operation))

The first 3 lines run the function, and then gets the return value, and then stores in variables. Finally, we run the calculate function and take hte return value and then put it in the print() function.

Our final code is:

# In calculate.py

# Calculator Functions
def add(x, y): return x+y
def subtract(x, y): return x-y
def multiply(x, y): return x*y
def divide(x, y):
  if (y == 0):
    return 'Cannot divide by 0 you dummy'
  else:
    return x/y

# Getting the input
def get_numeric_input():
  input_var= input('Enter a number: ')
  while (not input_var.isnumeric()):
    print('The input is not numeric, enter again: ')
    input_var = input('Enter a number: ')

  return int(input_var)

def get_operation_input():
  input_var = input('Enter an operation (+, -, *, /): ')
  while (input_var not in ['+', '-', '*', '/']):
    print('The operationis not among +, -, *, and /, enter again: ')
    input_var = input('Enter an operation (+, -, *, /): ')
  
  return input_var

# Perform the calculation
def calculate(x, y, operation):
  if (operation == '+'):
    return f'{x} + {y} = {add(x, y)}'
  elif (operation == '-'):
    return f'{x} - {y} = {subtract(x, y)}'
  elif (operation == '*'):
    return f'{x} * {y} = {multiply(x, y)}'
  elif (operation == '/'):
    return f'{x} / {y} = {divide(x, y)}'
  else:
    return "I do not understand that operation"

# Running the calculator
x = get_numeric_input()
y = get_numeric_input()
operation = get_operation_input()
print(calculate(x, y, operation))

Even more improvements:

  • We still can’t enter decimal numbers like 3.14. The isnumeric() function thinks that the decimal point . is not a number so it will think that 3.14 is not a number, specifically, an integer.
  • We’re limited only to the arithmetic operators. What about sin(x), cos(x), and other functions.
  • Our code is becoming quite too big to be on a single file. Also what if our friend needs this calculator and we need to send it over. All they need to see is the last 4 lines. So can we “hide” everything else?
  • I dislike the way we’re entering input. It is not calculator-like at all. In calculators, we enter the calculation in a single line. Like: 3/5 and we get the answer back. Is there a way of doing that?

Conclusion

In this part, we’ve taken a straightforward four-function calculator and progressively improved it by handling common errors and restructuring the code with functions. This approach not only makes the code cleaner and more readable but also sets the stage for adding more features in the subsequent parts of this series. In the next parts, we’ll address the above points of improvements.